function Entity(){
  this.name = null;
  this.uri = null;

  this.attributes = new Array();
  this.topics = new Array();
  this.resources = new Array();
  this.relatedEntities = new Array();
};

Entity.prototype.addAttribute = function(name, value){
  var attribute = {};
  attribute.name = name;
  attribute.value = value;
  this.attributes.push(attribute);
}
Entity.prototype.addTopic = function(name, href){
  var topic = {};
  if(typeof name != 'undefined' && name != '')
    topic.name = name;
  topic.href = href;
  this.topics.push(topic);
}
Entity.prototype.removeTopic = function(href) {
  for(var i=0; i < this.topics.length; i++){
    if(this.topics[i].href == href)
      this.topics.splice(i,1);
  }
}
Entity.prototype.addResource = function(name, href){
  var resource = {};
  resource.name = name;
  resource.href = href;
  this.resources.push(resource);
}
Entity.prototype.findResourceByHref = function(href){
  for(var i=0; i < this.resources.length; i++)
    if(this.resources[i].href == href)
      return this.resources[i];
  return null;
}
Entity.prototype.findResourceByName = function(name){
  for(var i=0; i < this.resources.length; i++)
    if(this.resources[i].name == name)
      return this.resources[i];
  return null;
}
Entity.prototype.addRelatedEntity = function(name, href, relationType){
  var relatedEntity = {};
  if(typeof name != 'undefined' && name != '')
    relatedEntity.name = name;
  relatedEntity.href = href;
  if(typeof relationType != 'undefined' && relationType != '')
    relatedEntity.relationType = relationType;
  this.relatedEntities.push(relatedEntity);
}


Entity.prototype.toXml = function() {
	var xmlStr = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
	xmlStr += "<entity>\n";
	for(var i = 0; i < this.attributes.length; i++){
		var k = this.attributes[i].name + "";
		var v = this.attributes[i].value + "";
		xmlStr += "<attribute name=\"" + k.toXml() + "\" value=\"" + v.toXml() + "\" />";
	}
	for(var i = 0; i < this.resources.length; i++){
		var k = this.resources[i].name + "";
		var v = this.resources[i].href + "";
		xmlStr += "<resource name=\"" + k.toXml() + "\" href=\"" + v.toXml() + "\" />";
	}
	for(var i = 0; i < this.topics.length; i++){
		var h = this.topics[i].href + "";
		xmlStr += "<topic href=\"" + h.toXml() + "\">";
		if(typeof this.topics[i].name != "undefined" && this.topics[i].name != ""){
		  var n = this.topics[i].name + "";
		  xmlStr += n.toXml();
		}
		xmlStr += "</topic>";
	}
	for(var i = 0; i < this.relatedEntities.length; i++){
		var h = this.relatedEntities[i].href + "";
		var rt = this.relatedEntities[i].relationType + "";
		xmlStr += "<relatedEntity href=\"" + h.toXml() + "\" relationType=\"" + rt.toXml() + "\">";
		if(typeof this.relatedEntities[i].name != "undefined" && relatedEntities.topics[i].name != ""){
		  var n = this.relatedEntities[i].name + "";
		  xmlStr += n.toXml();
		}
		xmlStr += "</relatedEntity>";
	}
	xmlStr += "</entity>";
	return xmlStr;
}

Entity.prototype.parseXml = function(xmlStr){
  var entity = new Entity();
  var xmlReader = Components.classes["@mozilla.org/saxparser/xmlreader;1"]
                          .createInstance(Components.interfaces.nsISAXXMLReader);
  xmlReader.contentHandler = {
    currentElement: null,
    tmpTopic: null,
    tmpRelatedEntity : null,

    startDocument: function() {},
		endDocument: function() {},

    startElement: function(uri, localName, qName, /*nsISAXAttributes*/ attributes) {
      this.currentElement = qName;
      //debug("[startElement] currentElement:" + this.currentElement ,1);

      if(qName == "attribute"){
        n = "";
        v = "";
        for(var i=0; i<attributes.length; i++) {
          if(attributes.getQName(i) == "name")
            n = attributes.getValue(i);
          if(attributes.getQName(i) == "value")
            v = attributes.getValue(i);
        }
        entity.addAttribute(n,v);
      }

      if(qName == "resource"){
        n = "";
        v = "";
        for(var i=0; i<attributes.length; i++) {
          if(attributes.getQName(i) == "name")
            n = attributes.getValue(i);
          if(attributes.getQName(i) == "href")
            v = attributes.getValue(i);
        }
        entity.addResource(n,v);
      }

      if(qName == "topic"){
        this.tmpTopic = {};
        this.tmpTopic.name = "";
        for(var i=0; i<attributes.length; i++)
          if(attributes.getQName(i) == "href")
            this.tmpTopic.href = attributes.getValue(i);
        //debug("[startElement] this.tmpTopic.href:" + this.tmpTopic.href ,1);
      }

      if(qName == "relatedEntity"){
        this.tmpRelatedEntity = {};
        this.tmpRelatedEntity.name = "";
        for(var i=0; i<attributes.length; i++){
          if(attributes.getQName(i) == "href")
            this.tmpRelatedEntity.href = attributes.getValue(i);
          if(attributes.getQName(i) == "relationType")
            this.tmpRelatedEntity.relationType = attributes.getValue(i);
        }
        //debug("[startElement] this.tmpTopic.href:" + this.tmpTopic.href ,1);
      }
    },

    endElement: function(uri, localName, qName) {
      //debug("[endElement] currentElement:" + this.currentElement + ", typeof:" + (typeof this.tmpTopic),1);
      if(this.currentElement == "topic" && this.tmpTopic != null){
        entity.addTopic(this.tmpTopic.name,this.tmpTopic.href);
        this.tmpTopic = null;
        //debug("[endElement] vp.topics.push:" + vp.topics.length ,1);
      }
      if(this.currentElement == "relatedEntity" && this.tmpRelatedEntity != null){
        entity.addRelatedEntity(this.tmpRelatedEntity.name, this.tmpRelatedEntity.href, this.tmpRelatedEntity.relationType);
        this.tmpRelatedEntity = null;
      }
      this.currentElement = null;
    },

    characters: function(value) {
      //debug("[characters] currentElement:" + this.currentElement + ", typeof:" + (typeof this.currentElement) + ", value:" + value,1);
      if((typeof this.currentElement) != "string")
        return;
      if(this.currentElement == "topic"){
        this.tmpTopic.name = value;
      }
      if(this.currentElement == "relatedEntity"){
        this.tmpRelatedEntity.name = value;
      }
    },
    processingInstruction: function(target, data) {},
    ignorableWhitespace: function(whitespace) {},
    startPrefixMapping: function(prefix, uri) {},
    endPrefixMapping: function(prefix) {},

    // nsISupports
    QueryInterface: function(iid) {
      if(!iid.equals(Components.interfaces.nsISupports) &&
         !iid.equals(Components.interfaces.nsISAXContentHandler))
        throw Components.results.NS_ERROR_NO_INTERFACE;
      return this;
    }
  }
  xmlReader.parseFromString(xmlStr, "text/xml");
  return entity;
}

Entity.prototype.httpGet = function(user, pass) {
	if(this.uri == null){
		return null;
	}
	var req = new customRequest('GET', this.uri, "");
	var http = new HTTPCore();
	if(typeof user == "string" && user != "")
	  http.auth(user, pass);
	var res = http.doOperation(req);
	debug("[entity.js::httpGet] Entity.httpGet URL:" + this.uri, 1);
	debug("[entity.js::httpGet] Entity.httpGet Response:" + http.response, 1);
	if(!res) return false;
	var res = this.parseXml(http.response);
	return res;
}

Entity.prototype.httpPut = function(user, pass) {
	if(this.uri == null){
		return false;
	}
	var content = this.toXml();
  var req = new customRequest('PUT', this.uri, content);
  var http = new HTTPCore();
	if(typeof user == "string" && user != "")
	  http.auth(user, pass);
	debug("[entity.js::httpPut] request uri:" + this.uri, 1);
	debug("[entity.js::httpPut] request body:" + content, 1);
	var res = http.doOperation(req);
	debug("[entity.js::httpPut] Entity.httpPut URL:" + this.uri, 1);
	debug("[entity.js:httpPut] Response Header:" + http.status, 1);
	debug("[entity.js::httpPut] Entity.httpPut Response:" + http.response, 1);
	return res;
}

Entity.prototype.httpDelete = function(user, pass) {
	if(this.uri == null){
		return false;
	}
  var req = new customRequest('DELETE', this.uri, "");
  var http = new HTTPCore();
	if(typeof user == "string" && user != "")
	  http.auth(user, pass);
	var res = http.doOperation(req);
	debug("[entity.js::httpDelete] Entity.httpDelete URL:" + this.uri, 1);
	debug("[entity.js::httpDelete] Entity.httpDelete Response:" + http.response, 1);
	return res;
}

function testCase(){
  /*var entity = new Entity();
  entity.addAttribute("name", "Entity for test");
  entity.addAttribute("type", "fragment");
  entity.addTopic("topic for test", "http://www.hypertopic.org/viewpoint/1/");
  entity.addResource("html", "http://www.hypertopic.org/");
  entity.addRelatedEntity("", "http://argos.vmware.org/argos/entity/", "partOf");
  var xml = entity.toXml();
  print(xml);*/
  var xml = '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE entity SYSTEM "http://argos.hypertopic.org/validator/dtd/entity.dtd"> <entity> <attribute name="name" value="Entity for test" /><attribute name="type" value="fragment" /><resource name="html" href="http://www.hypertopic.org/" /><topic href="http://www.hypertopic.org/viewpoint/1/">topic for test</topic><relatedEntity href="http://argos.vmware.org/argos/entity/" relationType="partOf"></relatedEntity></entity>';
  var entity = new Entity();
  entity = entity.parseXml(xml);
  xml = entity.toXml();
  print(xml);
}
//testCase();